//Jonathan Flessner
//Assignment 4
//11-May-2014
//Random Test Adventurer Card
//Adventurer - reveal cards from deck until you reveal 2 treasure cards.
//Put those treasure cards in your hand and discard the other revealed cards.
//If you have searched through all of the cards without finding two treasure
//cards then you only get the 0 or 1 treasure cards you did find.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

//to print all variables for examining
void variableDump(int hCards, int disCards, int deckCards, int preTreas, int postTreas, int numTreasure, int numTreasurePost, int oldTotal, int newTotal);

int main(){
	//variables
	int seed = 17;			//numerical seed for reproducing errors
	srand(seed);
	struct gameState gS;
	int testNum = 100000;	//num of tests to run
	int j = 0;				//test loop iterator
	int numPlayers = 0;		//num of players in game
	int p = 0;				//current player
	int i = 0;				//other loop iterator
	int hCards = 0;			//num of cards in hand
	int disCards = 0;		//num of cards in discard
	int deckCards = 0;		//num of cards in deck
	int card = 0;			//card identifier
	int preTreas = 0;		//num of treasure in hand before
	int postTreas = 0;		//num of treasure after
	int numTreasure = 0;	//num of treasure cards in deck,discard
	int numTreasurePost = 0;//num of treasure in deck,discard after
	
	//random testing
	for(j = 0; j < testNum; j++){
		//fill gamestate with random junk
		for (i = 0; i < sizeof(struct gameState); i++){
			((char *)&gS)[i] = rand() % 128;
		}
		//fill necessary things with realistic numbers
		numPlayers = rand() % 3 + 2;	//2, 3 or 4 players
		p = rand() % numPlayers;		//select random player (0,1,2,3) as p
		gS.whoseTurn = p;				//set turn to players turn
		hCards = rand() % 10 + 1;		//set handCount to random number less than 10 (from 0 - 9) but must have 1 to play
		gS.handCount[p] = hCards;		//set handCount
		//hand count could be higher but it becomes extremely unlikely, possibly impossible depending on cards
		//num of cards in discard and deck set to random less than MAX_DECK (500)
		//it seems this should probably be smaller for more realistic samples
		disCards = rand() % MAX_DECK;
		gS.discardCount[p] = disCards;
		deckCards = rand() % MAX_DECK;
		gS.deckCount[p] = deckCards;
		preTreas = 0;
		postTreas = 0;
		numTreasure = 0;
		numTreasurePost = 0;
		
		//set random hand using cards - 4,5,6 are treasure cards - make sure case of less than 2.
		for(i = 0; i < hCards; i++){
			card = rand() % 17;			//set random card from 0-16 (curse to great_hall)
			gS.hand[p][i] = card;
			if(card > 3 && card < 7){	//add to numTreasure if treasure
				preTreas++;
			}
		}
		//set random discards
		for(i = 0; i < disCards; i++){
			card = rand() % 17;			//set random card from 0-16 (curse to great_hall)
			gS.discard[p][i] = card;
			if(card > 3 && card < 7){	//add to numTreasure if treasure
				//gS.discard[p][i] = card + 3;	//purposefully no treasure - comment out numTreasure++ below
				numTreasure++;
			}
		}
		//set random deck
		for(i = 0; i < deckCards; i++){
			card = rand() % 17;			//set random card from 0-16 (curse to great_hall)
			gS.deck[p][i] = card;
			if(card > 3 && card < 7){	//add to numTreasure if treasure
				//gS.deck[p][i] = card + 3;	//purposefully no treasure - comment out numTreasure++ below
				numTreasure++;
			}
		}
		
		//play adventurer
		adventurerEffect(&gS);
		//get counts after effect
		//count treasure in hand
		for(i = 0; i < gS.handCount[p]; i++){
			if(gS.hand[p][i] > 3 && gS.hand[p][i] < 7){
				postTreas++;
			}
		}
		//count treasure in deck
		for(i = 0; i < gS.deckCount[p]; i++){
			if(gS.deck[p][i] > 3 && gS.deck[p][i] < 7){
				numTreasurePost++;
			}
		}
		//count treasure in discard
		for(i = 0; i < gS.discardCount[p]; i++){
			if(gS.discard[p][i] > 3 && gS.discard[p][i] < 7){
				numTreasurePost++;
			}
		}
		//tests
		int oldTotal = hCards + disCards + deckCards;
		int newTotal = gS.handCount[p] + gS.discardCount[p] + gS.deckCount[p];
		
		//IMPORTANT NOTE: this has been altered to account for found bug that adventurerEffect has a bug
		//where the card itself is not discarded. Once this is fixed the following statements should be
		//re-added to the tests
		/*
		if(numTreasure >= 2 && hCards + 1 != gS.handCount[p]){  //add two treasure to hand, discard adventurer
			printf("FAIL: Wrong cards in hand for 2 added treasures.\n");
			printf("Pre cards in hand: %d\n", hCards);
			printf("Post cards in hand: %d | Expected: %d\n", gS.handCount[p], hCards+1);
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		if(numTreasure == 1 && hCards != gS.handCount[p]){  //add one treasure to hand, discard adventurer
			printf("FAIL: Wrong cards in hand for 1 added treasures.\n");
			printf("Pre cards in hand: %d\n", hCards);
			printf("Post cards in hand: %d | Expected: %d\n", gS.handCount[p], hCards);
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		if(numTreasure == 0 && hCards - 1 != gS.handCount[p]){  //add zero treasure to hand, discard adventurer
			printf("FAIL: Wrong cards in hand for 0 added treasures.\n");
			printf("Pre cards in hand: %d\n", hCards);
			printf("Post cards in hand: %d | Expected: %d\n", gS.handCount[p], hCards - 1);
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		*/
		
		//test count of cards is the same - no cards trashed
		if(oldTotal != newTotal){
			printf("FAIL: Card counts don't match.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test num of treasures added to hand is expected
		if(numTreasure >= 2 && preTreas + 2 != postTreas){
			printf("FAIL: 2 treasure not added correctly.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test num of treasures added to hand is expected when only 1 treasure
		if(numTreasure == 1 && preTreas + 1 != postTreas){
			printf("FAIL: single treasure not added correctly.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test num of treasures added to hand is expected when 0 treasure added
		if(numTreasure == 0 && preTreas != postTreas){
			printf("FAIL: no treasure to add.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test treasures removed from deck/discard
		if(numTreasure >= 2 && numTreasure - 2 != numTreasurePost){
			printf("FAIL: treasures in deck/discard don't match.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test treasures removed from deck/discard
		if(numTreasure == 1 && numTreasure - 1 != numTreasurePost){
			printf("FAIL: single treasure not removed from deck/discard properly.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
		//test treasures removed from deck/discard
		if(numTreasure == 0 && numTreasure != numTreasurePost){
			printf("FAIL: no treasure to remove from deck/discard but count wrong.\n");
			variableDump(hCards, disCards, deckCards, preTreas, postTreas, numTreasure, numTreasurePost, oldTotal, newTotal);
		}
	}
	return 0;
}

void variableDump(int hCards, int disCards, int deckCards, int preTreas, int postTreas, int numTreasure, int numTreasurePost, int oldTotal, int newTotal){
	printf("Pre cards in hand: %d\n", hCards);
	printf("Pre cards in discard: %d\n", disCards);
	printf("Pre cards in deck: %d\n", deckCards);
	printf("Pre treasure in hand: %d\n", preTreas);
	printf("Post treasure in hand: %d\n", postTreas);
	printf("Pre treasure in deck/discard: %d\n", numTreasure);
	printf("Post treasure in deck/discard: %d\n", numTreasurePost);
	printf("Total cards pre: %d\n", oldTotal);
	printf("Total cards post: %d\n", newTotal);
}